feat(testing): cut over daily test suite to Kueue scheduling - #6014
feat(testing): cut over daily test suite to Kueue scheduling#6014sudheer-quad wants to merge 3 commits into
Conversation
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request migrates the slurm-gcp-v6-rocky-8 daily test suite to use Kueue for job scheduling within the hpc-toolkit-dev-2 project. The changes involve replacing the legacy build process with a containerized job execution model that leverages Kueue for queue management, retry logic, and better resource utilization. Additionally, the infrastructure code has been updated to support these new triggers and scheduling requirements. Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request migrates the slurm-gcp-v6-rocky8 daily integration test to run as a GKE Kueue job, introducing scripts to monitor Kueue jobs, wait for zone capacity, and check for retriable errors, alongside updating the Terraform provisioning configurations. Feedback on these changes highlights several issues: missing secret environment variables in the job manifest generation step, a lack of file existence verification in the retriable error check script, a missing set -e inside the subshell of the zone availability script, and the potential for the newly added backup file slurm-gcp-v6-rocky8_old.yaml to be accidentally discovered and scheduled by automated test scripts.
2deff8a to
e7e6910
Compare
e7e6910 to
cb9ad7f
Compare
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request migrates the daily integration tests (specifically slurm-gcp-v6-rocky8) to run on GKE Kueue. It introduces new scripts to monitor Kueue jobs, check for retriable errors, and wait for available zones, alongside updating the Terraform provisioning configuration. The review feedback identifies several critical improvements: preventing duplicate triggers by filtering out migrated tests from the old schedule, adding a timeout to the pod initialization loop in monitor_kueue_job.sh to prevent pipeline hangs, handling external job deletion gracefully, removing a backup YAML file that could clutter test discovery, and using mktemp instead of static paths in /tmp to avoid file conflicts.
| resource "google_cloudbuild_trigger" "daily_test_migrated" { | ||
| for_each = toset(var.kueue_migrated_tests) | ||
| name = "DAILY-test-${each.key}" | ||
| project = var.daily_tests_project_id | ||
| tags = [local.notify_chat_tag] |
There was a problem hiding this comment.
The original daily_test trigger and schedule in daily-tests.tf must be filtered to exclude var.kueue_migrated_tests to prevent duplicate triggers from being created and run in the old project. Currently, both the old and new triggers will be created for slurm-gcp-v6-rocky8 because list_tests_midnight still returns it.
| while true; do | ||
| POD_NAME=$(kubectl get pods -n "$NAMESPACE" --selector=job-name="$JOB_NAME" -o jsonpath='{.items[0].metadata.name}' 2>/dev/null) | ||
| if [ -n "$POD_NAME" ]; then | ||
| POD_PHASE=$(kubectl get pod "$POD_NAME" -n "$NAMESPACE" -o jsonpath='{.status.phase}' 2>/dev/null) | ||
| if [ "$POD_PHASE" = "Running" ] || [ "$POD_PHASE" = "Succeeded" ] || [ "$POD_PHASE" = "Failed" ]; then | ||
| echo "Pod $POD_NAME is $POD_PHASE. Ready to stream logs." | ||
| break | ||
| fi | ||
| echo "Pod $POD_NAME detected but is in phase: $POD_PHASE. Waiting for it to start running..." | ||
| fi | ||
| sleep 5 | ||
| done |
There was a problem hiding this comment.
If the GKE job fails to schedule or encounters a terminal error (such as ImagePullBackOff or invalid service account), the pod may remain in Pending or another non-running phase indefinitely. Since there is no timeout in this loop, the Cloud Build pipeline will hang until the 24-hour timeout is reached, incurring significant costs. Consider adding a reasonable timeout (e.g., 20 minutes) to this loop.
| while true; do | |
| POD_NAME=$(kubectl get pods -n "$NAMESPACE" --selector=job-name="$JOB_NAME" -o jsonpath='{.items[0].metadata.name}' 2>/dev/null) | |
| if [ -n "$POD_NAME" ]; then | |
| POD_PHASE=$(kubectl get pod "$POD_NAME" -n "$NAMESPACE" -o jsonpath='{.status.phase}' 2>/dev/null) | |
| if [ "$POD_PHASE" = "Running" ] || [ "$POD_PHASE" = "Succeeded" ] || [ "$POD_PHASE" = "Failed" ]; then | |
| echo "Pod $POD_NAME is $POD_PHASE. Ready to stream logs." | |
| break | |
| fi | |
| echo "Pod $POD_NAME detected but is in phase: $POD_PHASE. Waiting for it to start running..." | |
| fi | |
| sleep 5 | |
| done | |
| POD_INIT_TIMEOUT=1200 | |
| START_TIME=$SECONDS | |
| while true; do | |
| if [ $((SECONDS - START_TIME)) -gt $POD_INIT_TIMEOUT ]; then | |
| echo "Error: Pod initialization timed out after 20 minutes." >&2 | |
| exit 1 | |
| fi | |
| POD_NAME=$(kubectl get pods -n "$NAMESPACE" --selector=job-name="$JOB_NAME" -o jsonpath='{.items[0].metadata.name}' 2>/dev/null) | |
| if [ -n "$POD_NAME" ]; then | |
| POD_PHASE=$(kubectl get pod "$POD_NAME" -n "$NAMESPACE" -o jsonpath='{.status.phase}' 2>/dev/null) | |
| if [ "$POD_PHASE" = "Running" ] || [ "$POD_PHASE" = "Succeeded" ] || [ "$POD_PHASE" = "Failed" ]; then | |
| echo "Pod $POD_NAME is $POD_PHASE. Ready to stream logs." | |
| break | |
| fi | |
| echo "Pod $POD_NAME detected but is in phase: $POD_PHASE. Waiting for it to start running..." | |
| fi | |
| sleep 5 | |
| done |
| SUCCEEDED=$(kubectl get job "$JOB_NAME" -n "$NAMESPACE" -o jsonpath='{.status.succeeded}' 2>/dev/null) | ||
| FAILED=$(kubectl get job "$JOB_NAME" -n "$NAMESPACE" -o jsonpath='{.status.failed}' 2>/dev/null) | ||
|
|
||
| if [ "$SUCCEEDED" = "1" ] || [ "$FAILED" = "1" ]; then | ||
| break | ||
| fi |
There was a problem hiding this comment.
If the GKE job is deleted externally (e.g., by an administrator or another process), kubectl get job will fail and return a non-zero exit code, leaving both SUCCEEDED and FAILED empty. This will cause the loop to print "Logs disconnected but job is not finished. Reconnecting..." and loop infinitely. Check the exit status of kubectl get job to handle deletion gracefully.
| SUCCEEDED=$(kubectl get job "$JOB_NAME" -n "$NAMESPACE" -o jsonpath='{.status.succeeded}' 2>/dev/null) | |
| FAILED=$(kubectl get job "$JOB_NAME" -n "$NAMESPACE" -o jsonpath='{.status.failed}' 2>/dev/null) | |
| if [ "$SUCCEEDED" = "1" ] || [ "$FAILED" = "1" ]; then | |
| break | |
| fi | |
| if ! JOB_STATUS=$(kubectl get job "$JOB_NAME" -n "$NAMESPACE" -o jsonpath='{.status.succeeded}{" "}{.status.failed}' 2>/dev/null); then | |
| echo "Error: Job $JOB_NAME no longer exists or kubectl failed. Exiting." >&2 | |
| exit 1 | |
| fi | |
| read -r SUCCEEDED FAILED <<< "$JOB_STATUS" | |
| if [ "$SUCCEEDED" = "1" ] || [ "$FAILED" = "1" ]; then | |
| break | |
| fi |
| @@ -0,0 +1,76 @@ | |||
| # Copyright 2026 Google LLC | |||
There was a problem hiding this comment.
This backup file slurm-gcp-v6-rocky8_old.yaml should be removed from the repository. Keeping old/backup versions of files clutters the codebase and can cause issues with automated test discovery tools (like list_tests_midnight) which might scan all YAML files in this directory and attempt to provision duplicate triggers.
| while true; do | ||
| # Run the script in a subshell, streaming stdout and stderr to the console and a log file. | ||
| # To extract the exported variables, we have the subshell write them to a file. | ||
| set +e | ||
| ( | ||
| set -e | ||
| source /workspace/tools/cloud-build/find_available_zone.sh | ||
| # If it succeeds, these lines will execute and save the exports. | ||
| echo "export ZONE=\"${ZONE}\"" >/tmp/zone_export.sh | ||
| echo "export PROVISIONING_MODEL=\"${PROVISIONING_MODEL}\"" >>/tmp/zone_export.sh | ||
| ) 2>&1 | tee /tmp/zone_output.log | ||
|
|
||
| EXIT_CODE=${PIPESTATUS[0]} | ||
| set -e | ||
|
|
||
| if [ "$EXIT_CODE" -eq 0 ]; then | ||
| source /tmp/zone_export.sh | ||
| break | ||
| else | ||
| # Check if the failure was specifically due to zone capacity | ||
| if grep -q "Couldn't find a zone to deploy" /tmp/zone_output.log; then | ||
| echo "--- RETRYING in 5 minutes... ---" >&2 | ||
| sleep 300 | ||
| else | ||
| echo "--- FATAL ERROR: find_available_zone.sh failed due to a configuration or system error. Exiting. ---" >&2 | ||
| exit 1 | ||
| fi | ||
| fi | ||
| done |
There was a problem hiding this comment.
Using static file paths in /tmp (like /tmp/zone_export.sh and /tmp/zone_output.log) can lead to conflicts or security issues if multiple processes run in the same environment. Use mktemp to generate unique temporary files and ensure they are cleaned up on exit.
ZONE_EXPORT=$(mktemp)
ZONE_OUTPUT=$(mktemp)
trap 'rm -f "$ZONE_EXPORT" "$ZONE_OUTPUT"' EXIT
while true; do
# Run the script in a subshell, streaming stdout and stderr to the console and a log file.
# To extract the exported variables, we have the subshell write them to a file.
set +e
(
set -e
source /workspace/tools/cloud-build/find_available_zone.sh
# If it succeeds, these lines will execute and save the exports.
echo "export ZONE=\"${ZONE}\"" >"$ZONE_EXPORT"
echo "export PROVISIONING_MODEL=\"${PROVISIONING_MODEL}\"" >>"$ZONE_EXPORT"
) 2>&1 | tee "$ZONE_OUTPUT"
EXIT_CODE=${PIPESTATUS[0]}
set -e
if [ "$EXIT_CODE" -eq 0 ]; then
source "$ZONE_EXPORT"
break
else
# Check if the failure was specifically due to zone capacity
if grep -q "Couldn't find a zone to deploy" "$ZONE_OUTPUT"; then
echo "--- RETRYING in 5 minutes... ---" >&2
sleep 300
else
echo "--- FATAL ERROR: find_available_zone.sh failed due to a configuration or system error. Exiting. ---" >&2
exit 1
fi
fi
doneReferences
- In shell scripts, avoid creating temporary directories or files in /tmp with predictable names. Prefer using mktemp for secure temporary creation.
This PR transitions the slurm-gcp-v6-rocky-8 daily test suite to Kueue scheduling in the hpc-toolkit-dev-2 project.
Submission Checklist
NOTE: Community submissions can take up to 2 weeks to be reviewed.
Please take the following actions before submitting this pull request.